﻿using System;
using System.Collections.Generic;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using GalaSoft.MvvmLight.Messaging;
using mal.WP7.GoogleAnalytics.Business.Helpers;
using mal.WP7.GoogleAnalytics.Business.Repository;
using mal.WP7.GoogleAnalytics.Business.Resources;
using Microsoft.Phone.Scheduler;
using Microsoft.Phone.Shell;

namespace mal.WP7.GoogleAnalytics.Business.Tiles
{
    public class TileManager
    {
        #region Fields
        private const string LastTilesUpdateKey = "LastTilesUpdateKey";

        private List<string> websiteIds;
        #endregion

        #region Construction / Destruction

        #endregion

        #region enum, struct, class

        #endregion

        #region Properties

        #endregion

        #region Methods
        public void UpdateAllTiles()
        {
            this.websiteIds = null;
            string websitePageUrlFormat = string.Format(NavigationUriHelper.WebsitePageUrlFormat, string.Empty);
            Random rnd = new Random();
            foreach (ShellTile tile in ShellTile.ActiveTiles)
            {
                string tileUrl = tile.NavigationUri.ToString();
                if (tileUrl.ToUpperInvariant().StartsWith(websitePageUrlFormat.ToUpperInvariant()))
                {
                    if (this.websiteIds == null)
                    {
                        this.websiteIds = new List<string>();

                        Messenger.Default.Register<WebsitesAvailableMessage>(this, this.OnWebsitesAvailable);
                        Messenger.Default.Register<WebsiteStatisticsAvailableMessage>(this, this.OnWebsiteStatisticsAvailable);
                    }

                    string websiteId = tileUrl.Replace(websitePageUrlFormat, string.Empty);
                    this.websiteIds.Add(websiteId);
                }
            }

            this.UpdateWebsiteTiles();
        }

        public bool HasActiveWebsiteTiles()
        {
            string websitePageUrlFormat = string.Format(NavigationUriHelper.WebsitePageUrlFormat, string.Empty);

            foreach (ShellTile tile in ShellTile.ActiveTiles)
            {
                string tileUrl = tile.NavigationUri.ToString();
                if (tileUrl.ToUpperInvariant().StartsWith(websitePageUrlFormat.ToUpperInvariant()))
                {
                    return true;
                }
            }

            return false;
        }

        public void UpdateWebsiteTileIfExist(Website website)
        {
            string url = NavigationUriHelper.WebsitePageUrl(website.Id);
            ShellTile tileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString() == url);

            if (tileToFind != null)
            {
                this.GenerateWebsiteTile(website);
            }
        }

        public void ManageBackgroundTask(string taskDescription)
        {
            try
            {
                PeriodicTask periodicTask = new PeriodicTask("UpdateAllTiles");
                periodicTask.Description = taskDescription;
                periodicTask.ExpirationTime = DateTime.Now.AddDays(14);

                // If the agent is already registered with the system, 
                if (ScheduledActionService.Find(periodicTask.Name) != null)
                {
                    ScheduledActionService.Remove(periodicTask.Name);
                }

                if (this.HasActiveWebsiteTiles())
                {
                    ScheduledActionService.Add(periodicTask);

#if MOKE || DEBUG
                    ScheduledActionService.LaunchForTest(periodicTask.Name, TimeSpan.FromSeconds(20));
#endif
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        public void GenerateWebsiteTile(Website website)
        {
            if (website.DashboardDay != null && website.DashboardWeek != null)
            {
                string url = NavigationUriHelper.WebsitePageUrl(website.Id);
                StandardTileData tileData = new StandardTileData();
                double currentValue;
                double previousValue;
                double delta;

                tileData.Title = website.Name;

                currentValue = website.DashboardDay[website.DashboardDay.Count - 1].Value;
                previousValue = website.DashboardDay[website.DashboardDay.Count - 2].Value;
                delta = 100 * (currentValue - previousValue) / previousValue;
                tileData.BackgroundImage = this.GenerateWebsiteTileImage("day-" + website.Id, currentValue, delta, DateTime.Now.AddDays(-1).ToShortDateString());

                currentValue = website.DashboardWeekCurrentValue;
                previousValue = website.DashboardWeekPreviousValue;
                delta = 100 * (currentValue - previousValue) / previousValue;
                tileData.BackBackgroundImage = this.GenerateWebsiteTileImage("week-" + website.Id, currentValue, delta, ResourceText.Week);

                // Look to see whether the Tile already exists and if so, don't try to create it again.
                ShellTile tileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString() == url);

                if (tileToFind == null)
                {
                    // Create the Tile and pin it to Start. This will cause a navigation to Start and a deactivation of our application.
                    ShellTile.Create(new Uri(url, UriKind.RelativeOrAbsolute), tileData);
                }
                else
                {
                    tileToFind.Update(tileData);
                }
            }
        }

        public Uri GenerateWebsiteTileImage(string tileImageKey, double numberOfVisits
                                            , double delta, string periodText)
        {
            int imageSize = 173;
            string fileUrl = string.Format("Shared/ShellContent/{0}.jpg", tileImageKey.Replace(":", "-"));
            string deltaValue = string.Empty;

            Canvas panel = new Canvas();
            panel.Width = imageSize;
            panel.Height = imageSize;

            string tileBackgroundcolorKey = "PhoneAccentBrush";

            Brush tileBackgroundcolor = new SolidColorBrush(Color.FromArgb(187, 27, 161, 226));

            if (Application.Current.Resources.Contains(tileBackgroundcolorKey))
            {
                tileBackgroundcolor = (Brush)Application.Current.Resources[tileBackgroundcolorKey];
            }

            panel.Background = tileBackgroundcolor;

            Canvas content = new Canvas();
            content.Margin = new Thickness(5);
            panel.Children.Add(content);

            Image image = new Image();
            image.Width = 24;
            image.Source = new BitmapImage(new Uri("/Images/visitor.png", UriKind.Relative));
            content.Children.Add(image);

            Style PhoneTextNormalStyle = new Style(typeof(TextBlock));
            PhoneTextNormalStyle.Setters.Add(new Setter(TextBlock.FontFamilyProperty, new FontFamily("Segoe WP")));
            PhoneTextNormalStyle.Setters.Add(new Setter(TextBlock.FontSizeProperty, 20));
            PhoneTextNormalStyle.Setters.Add(new Setter(TextBlock.ForegroundProperty, new SolidColorBrush(Colors.White)));
            PhoneTextNormalStyle.Setters.Add(new Setter(TextBlock.MarginProperty, new Thickness(12, 0, 0, 0)));

            Style PhoneTextLargeStyle = new Style(typeof(TextBlock));
            PhoneTextLargeStyle.Setters.Add(new Setter(TextBlock.FontFamilyProperty, new FontFamily("Segoe WP")));
            PhoneTextLargeStyle.Setters.Add(new Setter(TextBlock.FontSizeProperty, 32));
            PhoneTextLargeStyle.Setters.Add(new Setter(TextBlock.ForegroundProperty, new SolidColorBrush(Colors.White)));
            PhoneTextNormalStyle.Setters.Add(new Setter(TextBlock.MarginProperty, new Thickness(12, 0, 0, 0)));


            TextBlock visitorsCount = new TextBlock();
            visitorsCount.Style = PhoneTextNormalStyle;
            visitorsCount.Text = numberOfVisits.ToString();
            Canvas.SetLeft(visitorsCount, 20);
            content.Children.Add(visitorsCount);

            int topPeriod = 25;
            int topDelta = 45;

            TextBlock period = new TextBlock();
            period.Style = PhoneTextNormalStyle;
            period.Text = periodText;
            period.Margin = new Thickness(2, 0, 0, 0);
            Canvas.SetTop(period, topPeriod);
            content.Children.Add(period);

            if (delta != 0)
            {
                Image arrow = new Image();
                arrow.Width = 48;
                arrow.Height = 48;
                if (delta > 0)
                {
                    arrow.Source = new BitmapImage(new Uri("/Images/stats-up.png", UriKind.RelativeOrAbsolute));
                }
                else
                {
                    arrow.Source = new BitmapImage(new Uri("/Images/stats-down.png", UriKind.RelativeOrAbsolute));
                }
                Canvas.SetTop(arrow, topPeriod + topDelta);
                content.Children.Add(arrow);
            }

            string format = "{0:F1}%";
            if (Math.Abs(delta) > 100 || delta == 0)
            {
                format = "{0:F0}%";
            }

            TextBlock deltaText = new TextBlock();
            deltaText.Text = string.Format(format, delta);
            deltaText.Style = PhoneTextLargeStyle;
            Canvas.SetLeft(deltaText, 55);
            Canvas.SetTop(deltaText, topPeriod + topDelta + 2);
            content.Children.Add(deltaText);

#if MOKE
            //TextBlock debug = new TextBlock();
            //debug.Text = DateTime.Now.ToString();
            //debug.Foreground = new SolidColorBrush(Colors.White);
            //Canvas.SetTop(debug, 130);
            //content.Children.Add(debug);
#endif
            using (IsolatedStorageFile fileStorage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (fileStorage.FileExists(fileUrl))
                {
                    fileStorage.DeleteFile(fileUrl);
                }

                using (var isoFileStream = fileStorage.CreateFile(fileUrl))
                {
                    WriteableBitmap wb = new WriteableBitmap(imageSize, imageSize);

                    wb.Render(panel, null);
                    wb.Invalidate();
                    Extensions.SaveJpeg(wb, isoFileStream, wb.PixelWidth, wb.PixelHeight, 0, 100);
                }
            }

            return new Uri("isostore:/" + fileUrl, UriKind.Absolute);
        }

        public DateTime? GetLastTilesUpdate()
        {
            DateTime? lastUpdate = null;

            if (IsolatedStorageSettings.ApplicationSettings.Contains(LastTilesUpdateKey))
            {
                lastUpdate = (DateTime)IsolatedStorageSettings.ApplicationSettings[LastTilesUpdateKey];
            }

            return lastUpdate;
        }

        public void SetLastTilesUpdate()
        {
            lock (LastTilesUpdateKey)
            {
                IsolatedStorageSettings.ApplicationSettings[LastTilesUpdateKey] = DateTime.Now;
            }
        }

        private void UpdateWebsiteTiles()
        {
            if (this.websiteIds != null)
            {
                if (WebsiteRepository.Instance.Websites != null)
                {
                    if (this.websiteIds != null)
                    {
                        for (int i = this.websiteIds.Count - 1; i >= 0; i--)
                        {
                            string websiteId = this.websiteIds[i];

                            Website website = WebsiteRepository.Instance.Websites.FirstOrDefault(w => w.Id == websiteId);

                            if (website != null)
                            {
                                if (website.DashboardDay != null && website.DashboardWeek != null)
                                {
                                    this.websiteIds.Remove(websiteId);
                                    this.UpdateWebsiteTileIfExist(website);
                                }

                            }
                        }
                    }
                }
            }
        }
        #endregion

        #region Events
        private void OnWebsitesAvailable(WebsitesAvailableMessage message)
        {
            Messenger.Default.Unregister<WebsitesAvailableMessage>(this, this.OnWebsitesAvailable);

            this.UpdateWebsiteTiles();

            if (this.websiteIds.Count == 0)
            {
                Messenger.Default.Unregister<WebsiteStatisticsAvailableMessage>(this, this.OnWebsiteStatisticsAvailable);
                Messenger.Default.Send<TileUpdateCompletedMessage>(new TileUpdateCompletedMessage());
            }
        }

        private void OnWebsiteStatisticsAvailable(WebsiteStatisticsAvailableMessage message)
        {
            if (message.Website.DashboardDay != null && message.Website.DashboardWeek != null)
            {
                this.UpdateWebsiteTileIfExist(message.Website);
                this.websiteIds.Remove(message.Website.Id);

                if (this.websiteIds.Count == 0)
                {
                    Messenger.Default.Unregister<WebsiteStatisticsAvailableMessage>(this, this.OnWebsiteStatisticsAvailable);
                    Messenger.Default.Send<TileUpdateCompletedMessage>(new TileUpdateCompletedMessage());

                    this.SetLastTilesUpdate();
                }
            }
        }
        #endregion
    }
}
